package com.sitech.ibnms.c3p.util;

import com.sitech.ibnms.c3p.form.CompareMo;
import com.sitech.ibnms.c3p.form.TextDiff;
import difflib.DiffRow;
import difflib.DiffRowGenerator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

/**
 * Created by qiyc on 2016/3/9.
 */
public class TextDiffUtil {
    public static final String Result_EQUAL = "EQUAL";
    public static final String Result_INSERT = "INSERT";
    public static final String Result_DELETE = "DELETE";
    public static final String Result_CHANGE = "CHANGE";
    public static List<List<TextDiff>> getDiff(List<String> oldLines,List<String> newLines){
        List<CompareMo> listCompareMo =compareAll(oldLines,newLines);
        List<List<TextDiff>> rowDiffs=new ArrayList<List<TextDiff>>();
        int rowNo=0;
        for(int i=0;i<listCompareMo.size();i++){
            rowDiffs.add(new ArrayList<TextDiff>());
            i=dealCompareLines(listCompareMo, rowDiffs,rowNo,i);
            rowNo++;
        }
        return rowDiffs;
    }
    public static List<CompareMo> compareAll(List<String> original, List<String> revised) {
        final DiffRowGenerator.Builder builder = new DiffRowGenerator.Builder();
        final DiffRowGenerator dfg = builder.build();
        final List<DiffRow> rows = dfg.generateDiffRows(original, revised);
        List<CompareMo> listCompareMo = new ArrayList<CompareMo>();
        int i=1,oldSize = original.size(),newSize = revised.size(),insertSize = 0,deleteSize = 0;
        for (final DiffRow diffRow : rows) {
            String tag = diffRow.getTag().toString();
            String oldLine = diffRow.getOldLine();
            String newLine = diffRow.getNewLine();
            if(Result_CHANGE.equals(tag)){
                boolean isInset = false;
                if ((i-insertSize) <= oldSize) {
                    if(oldLine!=null&& oldLine.trim().length()==0){
                        if(!original.get(i-1-insertSize).equals(oldLine)){
                            tag = Result_INSERT;
                            isInset = true;
                            insertSize ++;
                        }
                    }
                }
                if (!isInset) {
                    if ((i-deleteSize) <= newSize) {
                        if(newLine!=null&& newLine.trim().length()==0){
                            if(!revised.get(i-1-deleteSize).equals(oldLine)){
                                tag = Result_DELETE;
                                isInset = true;
                                deleteSize ++;
                            }
                        }
                    }
                }
            }
            listCompareMo.add(new CompareMo(
                    i, oldLine,
                    newLine,
                    tag
            ));
            i++;
        }
        return listCompareMo;
    }

    private static int dealCompareLines(List<CompareMo> listCompareMo,List<List<TextDiff>> rowDiffs,int rowNo,int i){
        CompareMo compareMo=listCompareMo.get(i);
        String tag=compareMo.getTag();
        String oldLine=compareMo.getOldLine();
        String newLine=compareMo.getNewLine();
        if(Result_CHANGE.equals(tag)){
            if(oldLine.length()>1){
                List<String> oldLines= Arrays.asList(oldLine.split(""));
                List<String> newLines=Arrays.asList(newLine.split(""));
                List<CompareMo> listCompareMoInLines =compareAll(oldLines,newLines);
                int changedCodeNoFrom=0,changedCodeNoTo=0;
                for(CompareMo listCompareMoInLine:listCompareMoInLines){
                    changedCodeNoTo=changedCodeNoFrom+listCompareMoInLine.getOldLine().length();
                    rowDiffs.get(rowNo).add(new TextDiff(listCompareMoInLine.getOldLine(),listCompareMoInLine.getNewLine(),listCompareMoInLine.getOldLine().equals(listCompareMoInLine.getNewLine()),changedCodeNoFrom,changedCodeNoTo));
                    changedCodeNoFrom=changedCodeNoTo;
                }
            }else{
                rowDiffs.get(rowNo).add(new TextDiff(oldLine,newLine,oldLine.equals(newLine),0,oldLine.length()));
            }
        }else if(Result_EQUAL.equals(tag)){
            rowDiffs.get(rowNo).add(new TextDiff(oldLine,newLine,oldLine.equals(newLine),0,oldLine.length()));
        }else if(Result_DELETE.equals(tag)){
            rowDiffs.get(rowNo).add(new TextDiff(oldLine,newLine,oldLine.equals(newLine),0,oldLine.length()));
        }else if(Result_INSERT.equals(tag)){
            rowDiffs.get(rowNo).add(new TextDiff(oldLine,newLine,oldLine.equals(newLine),0,0));
            if(listCompareMo.size()>i+1){
                i=i+1;
                dealCompareLines(listCompareMo, rowDiffs,rowNo,i);
            }
        }
        return i;
    }
    public static int returnInt(String str){
        try {
            Integer integer=Integer.valueOf(str);
            if(integer==null){
                integer=0;
            }
            return integer;
        }catch (Exception e){
            return 0;
        }
    }
    public static void mergeFind(List<TextDiff> textDiffs, String key, String text) {
        int begin = text.indexOf(key);
        int end = begin + key.length();
        boolean exitOrNot = true;
        for (TextDiff texts : textDiffs) {
            if (texts.isUsed() && !(texts.getEndNo() <= begin || end <= texts.getBeginNo())) {
                exitOrNot = false;
                break;
            } else if (!texts.isUsed() && texts.getBeginNo() >= end) {
                break;
            }
        }
        if (exitOrNot) {
            for (int i = 0; i < textDiffs.size(); i++) {
                TextDiff texts = textDiffs.get(i);
                int textBeg = texts.getBeginNo();
                int textEnd = texts.getEndNo();
                if (begin <= textBeg && textEnd <= end) {
                    texts.setUsed(true);
                    texts.setKey(key);
                } else if (!(textEnd <= begin || end <= textBeg)) {
                    int subtextBegin = begin > textBeg ? begin : textBeg;
                    int subBein = subtextBegin - textBeg;
                    int subEnd = end < textEnd ? end - textBeg : textEnd - textBeg;
                    String textBefore = texts.getOldText().substring(0, subBein);
                    String textmid = texts.getOldText().substring(subBein, subEnd);
                    String textAfter = texts.getOldText().substring(subEnd);
                    boolean isSame=texts.isSame();
                    List<TextDiff> addtextdiffs = new ArrayList<TextDiff>(3);
                    if (!textBefore.isEmpty()) {
                        addtextdiffs.add(new TextDiff(textBefore, isSame?textBefore:"", isSame, textBeg, textBeg + textBefore.length()));
                        textBeg += textBefore.length();
                    }
                    TextDiff newtextDiff = new TextDiff(textmid, isSame?textmid:"", isSame, textBeg + textBefore.length(), textBeg+ textBefore.length() + textmid.length());
                    newtextDiff.setUsed(true);
                    newtextDiff.setKey(key);
                    addtextdiffs.add(newtextDiff);
                    textBeg += textmid.length();
                    if (!textAfter.isEmpty()) {
                        addtextdiffs.add(new TextDiff(textAfter, isSame?textAfter:"", isSame, textBeg+ textBefore.length() + textmid.length(), textEnd));
                    }
                    textDiffs.remove(i);
                    textDiffs.addAll(i, addtextdiffs);
                    i += addtextdiffs.size() - 1;
                }
            }
        }
    }
    public static String returnMessage(String oldVal,String newVal){
        String returnVal="";
        if(oldVal!=null&&!oldVal.isEmpty()){
            if(newVal==null||newVal.isEmpty()){
                returnVal="["+removeEnterOfStr(oldVal)+":Deleted"+""+"]\n";
            }else if(!oldVal.equals(newVal)){
                returnVal="["+removeEnterOfStr(oldVal)+":ReplacedTo:"+removeEnterOfStr(newVal)+"]\n";
            }
        }
        return returnVal;
    }
    public static String removeEnterOfStr(String str){
        if(str==null||str.isEmpty()){
            return "";
        }else{
            while (str.startsWith(" ")||str.startsWith("\n")){
                str=str.substring(1,str.length());
            }
            while (str.endsWith(" ")||str.endsWith("\n")){
                str=str.substring(0,str.length()-1);
            }
            return str;
        }
    }
}
